package com.gengzp.rpc.proxy;

import com.gengzp.rpc.constants.RpcCommonConstants;
import com.gengzp.rpc.context.RemoteTransactionalContextHolder;
import com.gengzp.rpc.core.RemoteTransactionalCoreFunc;
import com.gengzp.rpc.core.RemoteTransactionalHandler;
import com.gengzp.rpc.core.RpcCoreFunc;
import com.gengzp.rpc.interceptor.RpcHttpRequestInterceptor;
import com.gengzp.rpc.model.dto.remoteTransaction.RemoteTransactionDto;
import com.gengzp.rpc.model.req.RpcRequestReq;
import com.gengzp.rpc.model.resp.RpcRequestResult;
import com.gengzp.rpc.utils.RpcHttpRequestUtils;
import com.gengzp.rpc.utils.RpcJsonUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.gengzp.rpc.constants.RemoteTransactionalConstants.REQUEST_ID_HEADER_KEY;

/**
 * @ClassName RpcInvocationHandler
 * @Description
 * @Author gengzp
 * @Date 2025/5/31 23:53
 */
public class RpcInvocationHandler implements InvocationHandler {

    private static final Logger logger = LoggerFactory.getLogger(RpcInvocationHandler.class);

    /**
     * 远程服务名称
     */
    private final String remoteServiceName;

    /**
     * 远程调用框架核心方法实例
     */
    private final RpcCoreFunc rpcCoreFunc;

    /**
     * 远程调用框架http请求拦截器
     */
    private final RpcHttpRequestInterceptor rpcHttpRequestInterceptor;

    /**
     * 远程事务核心方法实例
     */
    private final RemoteTransactionalCoreFunc remoteTransactionalCoreFunc;

    /**
     * 远程事务处理器实例
     */
    private final RemoteTransactionalHandler remoteTransactionalHandler;

    public RpcInvocationHandler(String remoteServiceName,
                                RpcCoreFunc rpcCoreFunc,
                                RpcHttpRequestInterceptor rpcHttpRequestInterceptor,
                                RemoteTransactionalCoreFunc remoteTransactionalCoreFunc,
                                RemoteTransactionalHandler remoteTransactionalHandler) {
        this.remoteServiceName = remoteServiceName;
        this.rpcCoreFunc = rpcCoreFunc;
        this.rpcHttpRequestInterceptor = rpcHttpRequestInterceptor;
        this.remoteTransactionalCoreFunc = remoteTransactionalCoreFunc;
        this.remoteTransactionalHandler = remoteTransactionalHandler;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 根据远程服务名获取所有实例url
        List<String> serviceUrls = new ArrayList<>();
        try {
            serviceUrls = rpcCoreFunc.searchOnlineServiceUrlByName(remoteServiceName);
        } catch (Exception ignored) {
        }
        if (serviceUrls == null || serviceUrls.isEmpty()) {
            throw new RuntimeException("远程服务未找到");
        }

        // 随机取出一个服务实例url
        String serviceUrl = String.format("http://%s%s", rpcCoreFunc.loadBalanceRemoteServiceUrl(serviceUrls), RpcCommonConstants.REMOTE_CALL_PRODUCER_URL);

        // 组装请求参数
        RpcRequestReq rpcRequestReq = new RpcRequestReq();
        rpcRequestReq.setRequestId(RemoteTransactionalContextHolder.getCurrentRequestId());
        rpcRequestReq.setConsumerServiceName(remoteServiceName);
        rpcRequestReq.setProducerServiceName(rpcCoreFunc.searchCurrentServiceName());
        rpcRequestReq.setInterfaceClass(proxy.getClass().getInterfaces()[0]);
        rpcRequestReq.setMethodName(method.getName());
        rpcRequestReq.setParameterTypes(method.getParameterTypes());
        rpcRequestReq.setArgs(args);

        // 通过拦截器拼接请求头
        Map<String, Object> headers = rpcHttpRequestInterceptor.setHttpRequestHeaderBeforeRemoteCall();
        // 请求头携带请求id, 后续将可被识别为远程调用
        headers.put(REQUEST_ID_HEADER_KEY, RemoteTransactionalContextHolder.getCurrentRequestId());

        // 发起http调用
        long startTime = System.currentTimeMillis();
        logger.info("开始远程调用: 服务名: [{}] -> [{}.{}()]", remoteServiceName, rpcRequestReq.getInterfaceClass().getName(), method.getName());
        RpcRequestResult result = RpcHttpRequestUtils.post(serviceUrl, headers, rpcRequestReq, RpcRequestResult.class);
        logger.info("远程调用结束, 耗时: [{}ms], 调用{}", System.currentTimeMillis() - startTime, result.getSuccess() ? "成功" : "失败, 原因: " + result.getErrorMessage());
        if (!result.getSuccess()) {

            // 远程调用失败, 若已经有远程事务提交, 则回滚当前请求所有已提交的远程事务
            List<RemoteTransactionDto> remoteTransactions = remoteTransactionalCoreFunc
                    .searchRemoteTransactionsByRequestId(RemoteTransactionalContextHolder.getCurrentRequestId());
            if (CollectionUtils.isNotEmpty(remoteTransactions)) {
                remoteTransactionalHandler.handleRemoteTransactionCallback(remoteTransactions);
            }

            throw new RuntimeException(String.format("远程调用失败: [%s]", result.getErrorMessage()));
        }
        Object data = result.getData();
        if (data == null) {
            return null;
        }

        return RpcJsonUtils.convert2Object(data, method.getGenericReturnType());
    }

}
